package com.portal.dao;

import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;
import javax.persistence.criteria.CriteriaQuery;

public abstract class GenericDAO<T> {
	private final static String UNIT_NAME = "CAR10";

	@PersistenceContext(unitName = UNIT_NAME)
	private EntityManager em;

	private Class<T> entityClass;

	public GenericDAO(Class<T> entityClass){
		this.entityClass = entityClass;
	}

	public void save(T entity){
		em.persist(entity);
	}

	public void delete(T entity){
		T entityToBeRemoved = em.merge(entity);
		em.remove(entityToBeRemoved);
	}

	public T update(T entity){
		return em.merge(entity);
	}

	public T find(Long entityID){
		return em.find(entityClass, entityID);
	}

	public List<T> findAll(){
		CriteriaQuery<T> cq = em.getCriteriaBuilder().createQuery(entityClass);
		cq.select(cq.from(entityClass));
		return em.createQuery(cq).getResultList();
	}

	@SuppressWarnings("unchecked")
	protected T findOneResult(String namedQuery, Map<String, Object> parameters) {
		T result = null;

		try {
			Query query = em.createNamedQuery(namedQuery);

			if(parameters != null && !parameters.isEmpty()){
				populateQueryParameters(query, parameters);
			}

			result = (T)query.getSingleResult();

		} catch (Exception e) {
			System.out.println("Error while running query: " + e.getMessage());
			e.printStackTrace();
		}

		return result;
	}

	@SuppressWarnings("unchecked")
	protected List<T> findResults(String namedQuery, Map<String, Object> parameters) {
		List<T> results = null;

		try {
			Query query = em.createNamedQuery(namedQuery);

			if(parameters != null && !parameters.isEmpty()){
				populateQueryParameters(query, parameters);
			}

			results = (List<T>)query.getResultList();

		} catch (Exception e) {
			System.out.println("Error while running query: " + e.getMessage());
			e.printStackTrace();
		}

		return results;
	}

	private void populateQueryParameters(Query query, Map<String, Object> parameters) {
		for(Entry<String, Object> entry : parameters.entrySet()){
			query.setParameter(entry.getKey(), entry.getValue());
		}
	}
}
